#include <iostream>
#include <typeinfo>
#include <assert.h>
#include <any>
// 设计一个存储任意报文（上下文）的通用容器
class Any
{
private:
    class holder
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info &type() = 0;
        virtual holder *clone() = 0;
    };
    template <class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val)
            : _val(val)
        {
        }
        virtual const std::type_info &type() // 获取子类对象中存储的数据类型
        {
            return typeid(T);
        }
        virtual holder *clone() // 针对当前对象本身，克隆出一个新的子类对象
        {
            return new placeholder(_val); // 重新构造一份新的数据
        }

    public:
        T _val;
    };
    holder *_content; // 通过多态调用子类的方法
public:
    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this;
    }

public:
    Any() : _content(nullptr)
    {
    }

    template <class T>
    Any(const T &val) : _content(new placeholder<T>(val))
    {
    }

    Any(const Any &other)
        : _content(other._content ? other._content->clone() : nullptr)
    {
        // 不能使用other的指针
    }

    ~Any()
    {
        delete _content;
    }

    // 返回子类对象保存的数据指针 获取到保存的上下文内容
    template <class T>
    T *get()
    {
        assert(typeid(T) == _content->type());
        return &((placeholder<T> *)_content)->_val; // 通过获取子类对象的指针获取值
    }

    // 重载=,其他容器进行赋值操作
    template <class T>
    Any &operator=(const T &val)
    {
        // 构造一个新的Any对象，进行swap之后，这个临时对象释放时，原来的数据也随着释放
        Any(val).swap(*this);
        return *this;
    }

    Any &operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};

class Test
{
    public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构" << std::endl;
    }

    Test(const Test& t)
    {
        std::cout << "拷贝构造" << std::endl;
    }
};

int main()
{
    std::any a;
    a = 10;
    int *pa = std::any_cast<int>(&a);
    std::cout << *pa << std::endl;

    a = std::string("nhhou");
    std::string *ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl;
    // Any a;
    // {
    //     Test t;
    //     a = t;
    // }
    // Any a;
    // a = 10;
    // int *pa = a.get<int>();
    // std::cout << *pa << std::endl;

    // a = std::string("hello world");
    // std::string *sp = a.get<std::string>();
    // std::cout << *sp << std::endl;
    return 0;
}